#ifndef KNAPSACKENVIRONMENT_H_
#define KNAPSACKENVIRONMENT_H_

#include "../Environment.h"
#include "../../Solution/BitEncoded/BitEncodedSolution.h"
#include "../../Solution/PermutationEncoded/PermutationEncodedSolution.h"
#include "../../Random/MyRandom.h"
#include "../../Crossover/SinglePoint/SinglePointCrossover.h"
#include "../../Crossover/TwoPoint/TwoPointCrossover.h"
#include "../../Crossover/Uniform/UniformCrossover.h"
#include "../../Exception/GA_Exception.h"
#include <vector>
#include <iostream>
#include <sstream>
#include <string>
#include <algorithm>
#include <fstream>
#include <string>

/******************************************************************
 * Class: KnapsackEnvironment
 *****************************************************************/

//TODO: should we pull these enums into an external library to avoid namespace collusions?
enum SolutionEncoding { BIT_ENCODED_SOLUTION = 1, PERMUTATION_ENCODED_SOLUTION = 2};
enum KnapsackEnvironmentCrossoverType{ SINGLE_POINT_CROSSOVER = 1, TWO_POINT_CROSSOVER = 2, UNIFORM_CROSSOVER = 3};

/** Struct for keeping track of one item in the knapsack.
 */
struct Item 
{
    double weight;  /**< The weight of a given item in the knapsack */
    double value;   /**< The value of a given item in the knapsack */
};

/** Environment for solving the Knapsack problem.
 */
template <typename T=PermutationEncodedSolution> class KnapsackEnvironment : public Environment
{
    public:
        KnapsackEnvironment();
        virtual ~KnapsackEnvironment();
        Crossover* configureCrossover();                           /**< Queries the user for a crossover type, then eturns a crossover usable by this environment       */
        Crossover* configureCrossover(KnapsackEnvironmentCrossoverType); /**< Returns a crossover usable by this environment       */
        double evaluateFitness(Solution*);                         /**< Evaluates the fitness of the given solution          */
        void generateRandomPopulation(vector<Solution*> &, unsigned int);   /**< Fills the provided vector with a random population   */
        string formatSolution(Solution* solution);                 /**< Outputs the solution with extra information          */
        void configure();                                          /**< Configures the environment                           */
        void configure(string);                            /**< Configures the environment from a file               */
        
        static string getName();
        static Environment* getEnvironment();                      /**< Static environment factory for knapsack environments */
        
    private:
        vector<Item> items;
        double maxAllowableWeight;
        double totalItemsWeight;
        double calcSolutionValue(T*);
        double calcSolutionWeight(T*);
        void populateItemsRandomly();
        void populateItemsFromFile(std::string filename);
        void boundValues(int&, double&, double&, double&, double&);
        bool configured;
        
        void init();
};

#endif /*KNAPSACKENVIRONMENT_H_*/
